﻿using Protocol;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net.Sockets;
using UnityEngine;

public class NetManager
{
    private static NetManager instance;

    /// <summary>
    /// 创建NetManagerUtil在Unity的存根，专门处理服务器信息的转发
    /// </summary>
    private static NetManagerUtil NetManagerUtil = (new GameObject("NetManagerUtil")).AddComponent<NetManagerUtil>();

    private Socket socket;

    private string ip = "127.0.0.1";

    private int port = 6650;

    private byte[] readbuff = new byte[1024];

    private bool isReading = false;

    private List<byte> cache = new List<byte>();

    public List<SocketModel> Messages = new List<SocketModel>();

    /// <summary>
    /// 单例对象
    /// </summary>
    public static NetManager Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new NetManager();
            }
            return instance;
        }

    }

    private NetManager()
    {
        try
        {
            //创建客户端连接对象
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //连接到服务器
            socket.Connect(ip, port);
            //开启异步消息接收 消息到达后会直接写入 缓冲区 readbuff
            socket.BeginReceive(readbuff, 0, 1024, SocketFlags.None, ReceiveCallBack, readbuff);
        }
        catch (Exception e)
        {
            Debug.Log(e.Message);
        }
    }

    /// <summary>
    /// 收到消息回调
    /// </summary>
    /// <param name="ar"></param>
    private void ReceiveCallBack(IAsyncResult ar)
    {
        try
        {
            //获取当前收到的消息长度()
            int length = socket.EndReceive(ar);
            byte[] message = new byte[length];
            Buffer.BlockCopy(readbuff, 0, message, 0, length);
            cache.AddRange(message);
            if (!isReading)
            {
                isReading = true;
                OnData();
            }
            //尾递归 再次开启异步消息接收 消息到达后会直接写入 缓冲区 readbuff
            socket.BeginReceive(readbuff, 0, 1024, SocketFlags.None, ReceiveCallBack, readbuff);
        }
        catch (Exception e)
        {
            Debug.Log("远程服务器主动断开连接");
            socket.Close();
        }
    }

    public void Write(byte type, int area, int command, object message)
    {
        ByteArray ba = new ByteArray();
        ba.Write(type);
        ba.Write(area);
        ba.Write(command);
        // 判断消息体是否为空  不为空则序列化后写入
        if (message != null)
        {
            ba.Write(SerializeUtil.Encode(message));
        }
        ByteArray arr1 = new ByteArray();
        // 要写入数据的长度，为了解决粘包问题
        arr1.Write(ba.Length);
        arr1.Write(ba.GetBuff());
        try
        {
            socket.Send(arr1.GetBuff());
        }
        catch (Exception e)
        {
            Debug.Log("网络错误，请重新登录" + e.Message);
        }
    }

    /// <summary>
    /// 缓存中有数据处理
    /// </summary>
    private void OnData()
    {
        // 长度解码
        byte[] result = Decode(ref cache);

        // 长度解码返回空 说明消息体不全，等待下条消息过来补全
        if (result == null)
        {
            isReading = false;
            return;
        }

        SocketModel message = MDecode(result);

        if (message == null)
        {
            isReading = false;
            return;
        }
        // 进行消息的处理
        Messages.Add(message);
        // 尾递归 防止在消息处理过程中 有其他消息到达而没有经过处理
        OnData();
    }

    /// <summary>
    /// 长度解码
    /// </summary>
    /// <param name="cache"></param>
    /// <returns></returns>
    public static byte[] Decode(ref List<byte> cache)
    {
        if (cache.Count < 4)
        {
            return null;
        }

        using (MemoryStream ms = new MemoryStream(cache.ToArray()))
        {
            using (BinaryReader br = new BinaryReader(ms))
            {
                // 从缓存中读取int型消息体长度
                int length = br.ReadInt32();
                // 如果消息体长度 大于缓存中数据长度 说明消息没有读取完 等待下次消息到达后再次处理
                if (length > ms.Length - ms.Position)
                {
                    return null;
                }
                //读取正确长度的数据
                byte[] result = br.ReadBytes(length);
                //清空缓存
                cache.Clear();
                //将读取后的剩余数据写入缓存
                cache.AddRange(br.ReadBytes((int)(ms.Length - ms.Position)));
                return result;
            }
        }
    }

    /// <summary>
    /// 数据模型解码
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static SocketModel MDecode(byte[] value)
    {
        ByteArray ba = new ByteArray(value);
        SocketModel model = new SocketModel();
        byte type;
        int area;
        int command;
        //从数据中读取 三层协议  读取数据顺序必须和写入顺序保持一致
        ba.Read(out type);
        ba.Read(out area);
        ba.Read(out command);
        model.Type = type;
        model.Area = area;
        model.Command = command;
        //判断读取完协议后 是否还有数据需要读取 是则说明有消息体 进行消息体读取
        if (ba.Readable)
        {
            byte[] message;
            //将剩余数据全部读取出来
            ba.Read(out message, ba.Length - ba.Position);
            //反序列化剩余数据为消息体
            model.Message = SerializeUtil.Decode(message);
        }
        ba.Close();
        return model;
    }
}

public sealed class NetManagerUtil : MonoBehaviour
{
    private IHandler loginHandler;

    private void Awake()
    {
        DontDestroyOnLoad(gameObject);
    }

    private void Start()
    {
        loginHandler = new LoginHandler();
    }

    private void Update()
    {
        while (NetManager.Instance.Messages.Count > 0)
        {
            SocketModel model = NetManager.Instance.Messages[0];
            StartCoroutine("MessageReceive", model);
            NetManager.Instance.Messages.RemoveAt(0);
        }
    }


    private void MessageReceive(SocketModel model)
    {
        switch (model.Type)
        {
            case GameProtocol.TYPE_LOGIN:
                loginHandler.MessageReceive(model);
                break;
        }
    }
}
